package lrts

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
)

const (
	urlCategory    = "http://www.lrts.me/book/index"
	urlBooks       = "http://www.lrts.me/book/category/"
	urlBookDetail  = "http://www.lrts.me/book/"
	urlBookChapter = "http://www.lrts.me/ajax/playlist/2/"
	regAllCategory = "category-item[\\W\\w]*?</li"
	regCategory    = "/book/category/([\\d]+)\">([\\W\\w]*?)<"
	regAllBooks    = "/book/([\\d]+)\" [\\w\\W]*?>([\\w\\W]*?)</a[\\w\\W]*?author\">([\\w\\W]*?)</a[\\w\\W]*?g-user\">([\\w\\W]*?)</a[\\w\\W]*?</div"
	regBookDetail  = "d-book-info[\\w\\W]*?src=\"([\\w\\W]*?)\"[\\w\\W]*?d-status[\\w\\W]*?\">([\\w\\W]*?)</i>[\\w\\W]*?章节：</span>([\\w\\W]*?)</li>[\\w\\W]*?<p>([\\w\\W]*?)</p>[\\w\\W]*?</section"
	regBookChapter = "section-item[\\w\\W]*?value=\"([\\w\\W]*?)\" name=\"source\"[\\w\\W]*?value=\"([\\d]+)\" name=\"number\"[\\w\\W]*?value=\"([\\d]+)\" name=\"share-fatherEntityId\"[\\w\\W]*?</li"
)

type Lrts struct {
	_db *sql.DB
}

func Obtain() (*Lrts, error) {
	db, err := sql.Open("mysql", "root:root@/lrts?charset=utf8")
	if err != nil {
		return nil, err
	}
	return &Lrts{db}, nil
}

func (lrts *Lrts) UpdateChapters() {
	rows, err := lrts._db.Query("select bookid from books order by bookid")
	if lrts.hasErr(err) {
		return
	}
	defer rows.Close()
	var bookid int
	for rows.Next() && !lrts.hasErr(rows.Scan(&bookid)) {
		fmt.Println(bookid)
		lrts.UpdateChapter(bookid)
	}
}

func (lrts *Lrts) UpdateChapter(bookid int) {
	var num = 1
	for 1 == 1 {
		fmt.Printf("UpdateChapter:%d\tnum:%d\n", bookid, num)
		cnt, err := lrts.wget(urlBookChapter + strconv.Itoa(bookid) + "/" + strconv.Itoa(num))
		if lrts.hasErr(err) {
			return
		}
		info := regexp.MustCompile(regBookChapter).FindAllStringSubmatch(cnt, -1)
		for i := 0; i < len(info); i++ {
			lrts.updateChapter(bookid, info[i][1], info[i][2], info[i][3])
		}
		if len(info) == 0 {
			return
		}
		num += 10
	}
}

func (lrts *Lrts) updateChapter(bookid int, source, number, time string) {
	rows, err := lrts._db.Query("select id from chapters where bookid=? and number=?", bookid, number)
	defer rows.Close()
	if lrts.hasErr(err) || !rows.Next() {
		stmt, err := lrts._db.Prepare("insert into chapters(bookid,number,source,time) values(?,?,?,?)")
		if lrts.hasErr(err) {
			return
		}
		stmt.Exec(bookid, number, source, time)
		stmt.Close()
	}
}

func (lrts *Lrts) UpdateBook(bookid int) {
	row := lrts._db.QueryRow("select chapter from books where bookid=?", bookid)
	var chapter int
	if lrts.hasErr(row.Scan(&chapter)) {
		cnt, err := lrts.wget(urlBookDetail + strconv.Itoa(bookid))
		if lrts.hasErr(err) {
			return
		}
		info := regexp.MustCompile(regBookDetail).FindStringSubmatch(cnt)
		stmt, err := lrts._db.Prepare("update books set photo=?,status=?,chapter=?,sketch=? where bookid=?")
		if lrts.hasErr(err) {
			return
		}
		stmt.Exec(info[1], info[2], info[3], info[4], bookid)
		stmt.Close()
		chapter, _ = strconv.Atoi(info[3])
	}
}

func (lrts *Lrts) UpdateBooks() {
	cates := lrts.getRootCate()
	for i := 0; i < len(cates); i++ {
		lrts.getBooks(cates[i])
	}
}
func (lrts *Lrts) getBooks(cate int) {
	var page = 1
	for 1 == 1 {
		fmt.Println("cate:" + strconv.Itoa(cate) + "\tpage:" + strconv.Itoa(page))
		cnt, err := lrts.wget(urlBooks + strconv.Itoa(cate) + "/hot/" + strconv.Itoa(page) + "/20")
		if lrts.hasErr(err) {
			return
		}
		books := regexp.MustCompile(regAllBooks).FindAllStringSubmatch(cnt, -1)
		if len(books) > 0 {
			for i := 0; i < len(books); i++ {
				lrts.updateBooks(books[i][1], books[i][2], books[i][3], books[i][4], strconv.Itoa(cate))
				bookid, _ := strconv.Atoi(books[i][1])
				lrts.UpdateBook(bookid)
			}
		} else {
			return
		}
		if len(books) < 20 {
			return
		}
		page += 1
	}
}

func (lrts *Lrts) updateBooks(bookid, name, author, guser, cate string) {
	rows, err := lrts._db.Query("select id from books where bookid=?", bookid)
	defer rows.Close()
	if lrts.hasErr(err) || !rows.Next() {
		stmt, err := lrts._db.Prepare("insert into books(bookid,name,author,guser,cate) values(?,?,?,?,?)")
		if lrts.hasErr(err) {
			return
		}
		stmt.Exec(bookid, name, author, guser, cate)
		stmt.Close()
	}
}

func (lrts *Lrts) getRootCate() []int {
	rows, err := lrts._db.Query("select cate from cates where parent=0")
	if lrts.hasErr(err) {
		return nil
	}
	var cates []int
	var cate int
	for rows.Next() && !lrts.hasErr(rows.Scan(&cate)) {
		cates = append(cates, cate)
	}
	rows.Close()
	return cates
}

func (lrts *Lrts) UpdateCategorys() {
	cnt, err := lrts.wget(urlCategory)
	if lrts.hasErr(err) {
		return
	}
	cates := regexp.MustCompile(regAllCategory).FindAllString(cnt, -1)
	for i := 0; i < len(cates); i++ {
		subCate := regexp.MustCompile(regCategory).FindAllStringSubmatch(cates[i], -1)
		for ii := 0; ii < len(subCate); ii++ {
			var parent = "0"
			if ii > 0 {
				parent = subCate[0][1]
			}
			lrts.updateCates(subCate[ii][1], subCate[ii][2], parent)
		}
	}
}

func (lrts *Lrts) updateCates(cate, name, parent string) {
	rows, err := lrts._db.Query("select id from cates where cate=?", cate)
	if lrts.hasErr(err) || !rows.Next() {
		rows.Close()
		stmt, err := lrts._db.Prepare("insert into cates(cate,name,parent) values(?,?,?)")
		if lrts.hasErr(err) {
			return
		}
		stmt.Exec(cate, name, parent)
		stmt.Close()
	} else {
		rows.Close()
		stmt, err := lrts._db.Prepare("update cates set name=?, parent=? where cate=?")
		if lrts.hasErr(err) {
			return
		}
		stmt.Exec(name, parent, cate)
		stmt.Close()
	}
}

func (lrts *Lrts) wget(url string) (string, error) {
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

func (lrts *Lrts) hasErr(err error) bool {
	if err != nil {
		fmt.Println(err.Error())
		return true
	}
	return false
}

func main() {
	lrts, err := Obtain()
	if err != nil {
		fmt.Println(err.Error())
	}
	// lrts.UpdateCategorys()
	// lrts.UpdateChapters()
	// lrts.getBooks(44)
	// lrts.UpdateBook(206)
	// lrts.UpdateChapter(10692)

}
